package org.dromara.common.core.utils;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.dromara.common.core.converter.EnhancedConversionService;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.DefaultConversionService;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.function.Function;

/**
 * Author: fly
 * Date: 2024/10/19
 **/
@Slf4j
public class ConverterUtils {

    private static ConversionService conversionService;

    public synchronized static BeanWrapper getBeanWrapper(Object obj) {
        BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(obj);
        if (conversionService == null) {
            conversionService = SpringUtils.getBean(DefaultConversionService.class);
            if (conversionService == null) {
                List<Converter> converterList = SpringUtils.getBeans(Converter.class);
                conversionService = new EnhancedConversionService(converterList);
                log.debug("new ConversionService instance: {}", EnhancedConversionService.class.getName());
            } else {
                log.debug("get ConversionService instance: {} by getBean", conversionService.getClass().getName());
            }
        }
        wrapper.setConversionService(conversionService);
        return wrapper;
    }

    /**
     * 类型class对象-转换方法
     */
    private static final Map<Class<?>, Function<String, Object>> fieldConverterMap = new HashMap<Class<?>, Function<String, Object>>() {{
        put(Integer.class, Integer::parseInt);
        put(Long.class, Long::parseLong);
        put(Double.class, Double::parseDouble);
        put(BigDecimal.class, BigDecimal::new);
        put(Float.class, Float::parseFloat);
        put(Date.class, D::fuzzyConvert);
        put(Boolean.class, StringUtils::isTrue);
    }};


    /**
     * 转换为field对应的类型
     *
     * @param value
     * @param field
     * @return
     */
    public static Object convertValueToFieldType(Object value, Field field) {
        if (value == null) {
            return null;
        }
        return convertValueToFieldType(value, field.getType());
    }

    /**
     * 转换为field对应的类型
     *
     * @param value
     * @param fieldType
     * @return
     */
    public static Object convertValueToFieldType(Object value, Class<?> fieldType) {
        if (value == null) {
            return null;
        }
        if (value.getClass().equals(fieldType)) {
            return value;
        }
        String valueStr = S.valueOf(value);
        if (fieldConverterMap.containsKey(fieldType)) {
            return fieldConverterMap.get(fieldType).apply(valueStr);
        } else if (LocalDate.class.equals(fieldType) || LocalDateTime.class.equals(fieldType)) {
            Date dateVal = (value instanceof Date) ? (Date) value : D.fuzzyConvert(valueStr);
            if (dateVal == null) {
                return null;
            }
            ZonedDateTime zonedDateTime = dateVal.toInstant().atZone(ZoneId.systemDefault());
            return LocalDateTime.class.equals(fieldType) ? zonedDateTime.toLocalDateTime() : zonedDateTime.toLocalDate();
        } else if (Serializable.class.isAssignableFrom(fieldType)) {
            if (value instanceof String) {
                return valueStr;
            }
            return JSON.parseObject(valueStr, fieldType);
        }
        return value;
    }


}
